package com.foton.lotterydomain.strategy.service.algorithm.impl;

import com.foton.lotterydomain.strategy.model.vo.AwardRateInfo;
import com.foton.lotterydomain.strategy.service.algorithm.IDrawAlgorithm;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author RenPu
 * @Date 2023/11/24 14:10
 * @Version 1.0
 * @Description: 基础算法实现-【共用的算法逻辑】
 * 抽象类不用全部实现接口的方法，根据需要进行实现接口方法
 **/
public abstract class BaseAlgorithm implements IDrawAlgorithm {

    // 斐波那契散列增量，逻辑：黄金分割点：(√5 - 1) / 2 = 0.6180339887，Math.pow(2, 32) * 0.6180339887 = 0x61c88647
    private final int HASH_INCREMENT = 0x61c88647;

    // 数组初始化长度
    private final int RATE_TUPLE_LENGTH = 128;

    // 存放概率与奖品对应的散列结果，strategyId -> rateTuple
    protected Map<Long, String[]> rateTuplestateMap = new ConcurrentHashMap<>();

    // 奖品区间概率值，strategyId -> [awardId->begin、awardId->end]
    protected Map<Long, List<AwardRateInfo>> awardRateInfostateMap = new ConcurrentHashMap<>();


    /**
     * 初始化概率数据
     *
     * @param strategyId        策略ID
     * @param awardRateInfoList 奖品概率配置集合 「值示例：AwardRateInfo.awardRate = 0.04」
     */
    @Override
    public void initRateTuple(Long strategyId, List<AwardRateInfo> awardRateInfoList) {
        // 保存奖品概率信息
        awardRateInfostateMap.put(strategyId, awardRateInfoList);

        // 存放概率与奖品对应的散列结果，strategyId -> rateTuple
        String[] rateTuple = rateTuplestateMap.computeIfAbsent(strategyId, k -> new String[RATE_TUPLE_LENGTH]);
        int cursorVal = 0;
        for (AwardRateInfo awardRateInfo : awardRateInfoList) {
            int rateVal = awardRateInfo.getAwardRate().multiply(new BigDecimal(100)).intValue();
            // 循环填充概率范围值，生成散列的值与奖品ID进行映射
            for (int i = cursorVal + 1; i <= (rateVal + cursorVal); i++) {
                rateTuple[hashIdx(i)] = awardRateInfo.getAwardId();
            }

            cursorVal += rateVal;
        }
    }


    /**
     * 斐波那契（Fibonacci）散列法，计算哈希索引下标值
     *
     * @param val 值
     * @return 索引
     */
    protected int hashIdx(int val) {
        int hashCode = val * HASH_INCREMENT + HASH_INCREMENT;
        return hashCode & (RATE_TUPLE_LENGTH - 1);
    }


    /**
     * 判断【是否】被初始化数据
     *
     * @param strategyId
     * @return
     */
    @Override
    public boolean isExistRateTuple(Long strategyId) {
        return rateTuplestateMap.containsKey(strategyId);
    }


}
